iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 16
1
Modern Web

Angular 全集中筆記系列 第 16

第 16 型 - Angular 生命週期 (Lifecycle) - AfterContentInit / AfterContentChecked

  • 分享至 

  • xImage
  •  

在上篇說明了 Angular 幾個生命週期鉤子方法 (Lifecycle hook methods),而這篇將繼續說明 AfterContentInitAfterContentChecked 兩個鉤子方法 (hook methods);並新增 PageContainer 與 PageTitle 兩個元件實作,讓待辦事項應用程式的每個頁面有一樣的版型。

前置作業

由於預計要實作的元件功能較不同於待辦事項,因此利用 Angular CLI 建立 UiModule,並在此建立 PageContainer 與 PageTitle 兩個元件,並在 page-container.component.css 中加入頁面標題的樣式。

div.page-title {
  border-bottom: solid 1px rgba(0, 0, 0, 0.12);
  padding-top: 1em;
  padding-left: 1em;
}

接著在 PageTitle 元件加入 pageTitle 輸入屬性,並利用 <h2> 標籤顯示在頁面上。

@Component({
  selector: "app-page-title",
  templateUrl: "./page-title.component.html",
  styleUrls: ["./page-title.component.css"],
})
export class PageTitleComponent {
  @Input() pageTitle: string;
}
<h2>{{ pageTitle }}</h2>

利用 <ng-content> 元素來由外部指定需顯示內容

在 Angular 應用程式中,除了可以透過 @Input() 裝飾器可以把資料傳入元件,還可以如活字排版一般,利用 <ng-content> 元素在元件中預留空間,在使用該元件的時候才會傳入此空間的 HTML 內容。因此,直接在 page-container.component.html 檔案使用 <ng-content> 元素。

<ng-content></ng-content>

然後在 app.component.html 中就可使用 PageContainer 元件,並將原內容程式放在此標籤內。

<app-page-container>
  <div>
    <span>
      <button type="button" (click)="onLoad()">載入資料</button>
      <button type="button" (click)="onClear()">清空資料</button>
    </span>
    <span>實際完成率:{{ completeRate | percent: '1.0-2' }}</span>
  </div>
  <app-task-list [tasks]="tasks"></app-task-list>
  <pre>{{ tasks | json }}</pre>
</app-page-container>

指定 <ng-content> 元素 select 屬性設定標題

在 Angular 應用程式中,透過選擇器指定方式,可用來決定元件 (Component) 與指令 (Direcitve) 的使用方式;也可以在元件內預留多個空間的需求時,利用 <ng-content> 元素的 select 屬性來指定所需套用的選擇器對象。

對象 定義方式 範例
標籤 (tag) 標籤名 h2
樣式類別 .類別名稱 .title-text
屬性 (attribute) [屬性名稱] [title-text]

接下來,在 app.component.html 使用 <app-page-title> 標籤,並指定所需要的標題內容。

<app-page-container>
  <app-page-title pageTitle="待辦事項清單"></app-page-title>
  <div>
    <span>
      <button type="button" (click)="onLoad()">載入資料</button>
      <button type="button" (click)="onClear()">清空資料</button>
    </span>
    <span>實際完成率:{{ completeRate | percent: '1.0-2' }}</span>
  </div>
  <app-task-list [tasks]="tasks"></app-task-list>
  <pre>{{ tasks | json }}</pre>
</app-page-container>

最後,在 page-container.component.html 設定 <ng-content> 元素的 select 屬性值為 app-page-title 即可。

<div class="page-title">
  <ng-content select="app-page-title"></ng-content>
</div>
<ng-content></ng-content>

Result

內容投影初始與變更

當元件利用 <ng-content> 元素接收外部指定的 HTML 內容時,可以透過 @ContentChild 裝飾器的屬性來查詢到傳入的子元件。在 Angular 將外部內容投影至元件內時,會呼叫 ngAfterContentInit()ngAfterContentChecked() 兩個鉤子方法 (hook method)。前者會在 onDoCheck() 事件後觸發,且在整個生命週期 (Lifecycle) 只會呼叫一次,在此方法中會初始化 @ContentChild 屬性。後者則是在 ngAfterContentInit() 執行完觸發,並且也會在每次的 ngDoCheck() 之後執行。

@Component({
  selector: "app-page-container",
  templateUrl: "./page-container.component.html",
  styleUrls: ["./page-container.component.css"],
})
export class PageContainerComponent
  implements OnInit, DoCheck, AfterContentInit, AfterContentChecked {
  @ContentChild(PageTitleComponent) title: HTMLElement;

  constructor() {}

  ngOnInit(): void {
    console.log("PageContainerComponent - ngOnInit");
  }

  ngDoCheck(): void {
    console.log("PageContainerComponent - ngDoCheck");
  }

  ngAfterContentInit(): void {
    console.log("PageContainerComponent - ngAfterContentInit", this.title);
  }

  ngAfterContentChecked(): void {
    console.log("PageContainerComponent - ngAfterContentChecked");
  }
}

page-container.component.ts 中加入 @ContentChild 屬性,以取得 AppComponent 所傳入的 PageTitle 元件,並實作各事件介面,以透過 Chorme DevTools 中可以觀察此 ngAfterContentInit()ngAfterContentChecked() 方法的觸發時間點。

@ContentChild 裝飾器會取得單個子元件實體;若需要取得多個子元件時則使用 @ContentChildren,其型別會是 QueryList 的泛型型別。

生命週期

結論

這一篇利用 <ng-content> 元素來實作了將 HTML 內容傳入元件內,並說明了 AfterContentInitAfterContentChecked 兩個生命週期鉤子 (Lifecycle hook method),實作程式碼放在 Github。下一篇將會說明剩下的兩個生命週期鉤子 (Lifecycle hook method) - AfterViewInitAfterViewChecked


上一篇
第 15 型 - Angular 生命週期 (Lifecycle) - onChanges / onInit / doCheck / onDestroy
下一篇
第 17 型 - Angular 生命週期 (Lifecycle) - AfterViewInit / AfterViewChecked
系列文
Angular 全集中筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言